<?php
// TODO: handle ids like LazyReferenceProperty
class Pageley_Mapper_LazyValueListProperty extends Pageley_Domain_ValueListProperty {

	private $entity;
	private $attribute;
	private $valueProvider;
	private $initialized;
	
	public function __construct($entity, $attribute) {
	    parent::__construct();
	    Pageley_Checks::parameterNotNull($entity, "Entity", "Pageley_Domain_Entity");
	    Pageley_Checks::parameterNotNull($attribute, "Attribute", "Pageley_Domain_Attribute");
		$this->entity = $entity;
		$this->attribute = $attribute;
		$this->setValue(null);
		$this->initialized = false;
	}

    public function setValueProvider($valueProvider) {
        Pageley_Checks::parameterNotNull($valueProvider, "Value provider", "Pageley_Mapper");
        $this->valueProvider = $valueProvider;
    }
	
	public function getValue($load = true) {
		$values = parent::getValue();
		if(!$this->initialized && $load) {
            $this->initialized = true;
            if($this->attribute->isManyToMany()) {
                $values = $this->getManyToMany();
            } else {
                $values = $this->getOneToMany();
            }
            parent::setValue($values);
		}
		return $values;
	}
    
    private function getManyToMany() {
        Pageley_Checks::propertyBeenSet($this->valueProvider, "Value provider", "Pageley_Mapper");
        $referencedType = $this->attribute->getDecoratedAttribute()->getType();
        $referencingType = $this->entity->getType();
        $relationType = $this->attribute->getRelationType($referencingType);
        $query = new Pageley_Query_Basic($relationType, 
            new Pageley_Query_Condition_Equals(Pageley_Util_String::uncapitalize($referencingType->getName()), $this->entity));
        $results = $this->valueProvider->query($query);
        return new Pageley_Mapper_ManyToManyMap($results, $relationType, Pageley_Util_String::uncapitalize($referencedType->getName()), $this->entity);
    }
    
    private function getOneToMany() {
        Pageley_Checks::propertyBeenSet($this->valueProvider, "Value provider", "Pageley_Mapper");
        $inversePropertyName = $this->attribute->getInversePropertyName();
        $referencedType = $this->attribute->getDecoratedAttribute()->getType();
        $referencingType = $this->entity->getType();
        if($inversePropertyName === null) {
            foreach($referencedType->getAttributes() as $propertyName => $attribute) {
                if($attribute->isReference() && $attribute->getType() === $referencingType) {
                    if($inversePropertyName !== null) {
                        throw new Pageley_Mapper_Exception("Cannot derive inverse property name for attribute " . $this->attribute . ", multiple candidates found. Please specify which property is the right one using inversePropertyName on the one-to-many relationship.");
                    }
                    $inversePropertyName = $propertyName;
                }
            }
            if($inversePropertyName === null) {
                throw new Pageley_Mapper_Exception("A one-to-many relation requires an inverse attribute on the referenced type. Please place an attribute on " . $referencedType . " referencing back to " . $referencingType . ".");
            }
        }
        $query = new Pageley_Query_Basic($referencedType, new Pageley_Query_Condition_Equals($inversePropertyName, $this->entity));
        return $this->valueProvider->query($query);
    }
	
	public function isInitialized() {
		return $this->initialized;
	}
}